<?php
namespace app\index\controller;

use app\index\controller\Cronrecent;
use app\index\controller\Server;
use app\index\model\LLogin;
use app\index\model\LRegister;
use app\index\model\Retention;
use app\recharge\model\Verify;
use think\Controller;
use think\Log;

class Compute extends Controller
{
    /*
     * 留存计算数组
     *
     * '1' 注册用户数，日活跃用户计算
     * '2' 次日留存计算
     * '3' 3日留存
     * '4' 4日留存
     * '5' 5日留存
     * '6' 6日留存
     * '7' 7日留存
     * '15' 15日留存
     * '30' 30日留存
     */
    private $nodes = [1, 2, 3, 4, 5, 6, 7, 15, 30];
    /*
     * 生命周期数组
     *
     * '1' 次日生命周期价值
     * '3' 3日生命周期价值
     * '7' 7日生命周期价值
     */
    private $ltv_nodes = [1, 3, 7];

    public function _initialize()
    {

        $this->lregister = new LRegister();
        $this->llogin    = new LLogin();
        $this->verify    = new Verify();

        # 记录开服日期
        $this->server        = new Server();
        $this->new_open_date = $this->server->getOpenDate();
    }
    /**
     * 手动更新留存
     * @DateTime 2018-02-04
     * @return   [type]
     */
    public function manualUpdateRetention()
    {

        //更新最新的登录及注册记录
        $Cronrecent = new Cronrecent();
        $Cronrecent->updateToRecent();

        //计算最新用户留存及用户生命价值
        //
        $calcDate = $this->getMostRecentDate();

        $this->doRetComputingToRecent($calcDate);
        $this->doLTVComputingToRecent($calcDate);

        //返回成功信息
        //
        $output['success'] = true;
        $output['msg']     = '完成数据更新';

        return json($output);
    }
    /**
     * 获取Character、Llogin、Lregister表最新记录
     *
     * @return   void
     */
    public function updateToRecent()
    {
        $Cronrecent = new Cronrecent();
        $Cronrecent->updateToRecent();
    }

    /**
     * 计算最近日期的留存率
     *
     * @return   [type]
     */
    public function doRetComputingToRecent($datefrom = null)
    {

        if ($datefrom) {
            $this->computeReversedFrom($datefrom);
        }
    }

    /**
     * 计算最近日期的留存率
     *
     * @return   [type]
     */
    public function doLTVComputingToRecent($datefrom = null)
    {

        if ($datefrom) {
            $this->computeLTVFrom($datefrom);
        }
    }

    /**
     * 计算用户生命周期价值
     *
     * @return   [type]
     */
    public function computeLTVFrom($from_date = null)
    {
        //计算终止日期 == 昨天

        $end_date = date("Y-m-d", strtotime("-1 day"));

        //起始日期到终止日期之间的天数

        $days = floor((strtotime($end_date) - strtotime($from_date)) / 86400);

        //开服日期

        $open_date = $this->getOpenDate();

        //计算区间
        //
        for ($i = 0; $i <= $days; $i++) {

            //起始计算日期
            //
            $startDate = date("Y-m-d", (strtotime($from_date) + 3600 * 24 * $i));


            //遍历生命周期计算区间
            //
            foreach ($this->ltv_nodes as $day) {
                
                $ltv = [];

                //留存模型实例化
                //
                $Retention = new Retention();

                //计算结果数据数组
                //
                $res = [];

                //计算日期
                //
                $calcDate = $startDate;
                $regDate  = date('Y-m-d', strtotime($startDate) - 3600 * 24 * $day);

                if ($regDate >= $open_date) {

                    $ltv['date'] = $regDate;

                    //计算注册日期开始，第 $day 天的留存数
                    $v = $this->lregister->getLTV($regDate, $calcDate);

                    $ltv['LTV' . $day] = empty($v) ? 0 : $v;

                    //更新注册日期开始，第 $day 天的用户生命价值

                    $Retention->isUpdate(true)->save($ltv, ['date' => $regDate]);

                }
            }
        }
    }

    /**
     * 获取最新的计算日期
     *
     * 如果所计算的日期大于昨天则返回false，表示不必计算
     *
     * @return   void
     */
    public function getMostRecentDate($datefrom = null)
    {

        // 留存表计算最近日期
        //
        $Retention = new Retention();

        if (!empty($datefrom)) {

            $recent = $datefrom;

        } else {

            $date = $Retention->getRecentDate();

            /**
             * 如果是空表则返回开服日期
             */
            if (empty($date)) {

                $date = $this->new_open_date;
                return $date;

            } else {

                $recent = $date;
            }
        }

        $yesterday = date('Y-m-d', strtotime("-1 day"));

        // 如果最新日期已经晚于等于昨天则不必计算，并返回false
        //
        if (strtotime($recent) >= strtotime($yesterday)) {

            return false;

        } else {

            // 距今最近计算日期 = 最近日期 + 1天
            return date('Y-m-d', (strtotime($recent) + 3600 * 24));
        }
    }

    /**
     * 获取配置表开服日期
     * @return   [type]
     */
    public function getOpenDate()
    {
        return ($this->new_open_date);
    }

    /**
     * 逆序留存计算
     * @return   void
     */
    public function computeReversedFrom($from_date)
    {

        //留存计算终止日期 == 昨天

        $end_date = date("Y-m-d", strtotime("-1 day"));

        //起始日期到终止日期的天数

        $days = floor((strtotime($end_date) - strtotime($from_date)) / 86400);

        //开服日期

        $open_date = $this->getOpenDate();

        for ($i = 0; $i <= $days; $i++) {

            //起始计算日期
            //
            $startDate = date("Y-m-d", (strtotime($from_date) + 3600 * 24 * $i));

            //遍历留存计算日期
            //
            foreach ($this->nodes as $day) {

                //留存模型实例化
                //
                $model = new Retention();

                //数据数组
                //
                $res = [];

                $regDate = $startDate;

                //玩家注册日期和开服时间比较,如果注册日期大于开服日期，计算该节点用户留存

                if (strtotime($regDate) >= strtotime($open_date)) {

                    if (1 === $day) {

                        $res = [];

                        //计算新注册人数及日活跃人数

                        $res['date']        = $regDate;
                        $res['DAU']         = $this->llogin->getDAU($regDate);
                        $res['DPU']         = $this->verify->getPayUserTotal($regDate);
                        $res['DPM']         = $this->verify->getPayTotal($regDate);
                        $res['register']    = $this->lregister->getRegTotal($regDate);
                        $res['total']       = $this->lregister->getRegGrandTotal($regDate);
                        $res['create_time'] = date('Y-m-d H:i:s');

                        $res['server_id']  = 1;
                        $res['channel_id'] = 'IOS';

                        //dump($res);

                        //保存昨天的新注册及日活跃人数

                        $model->isUpdate(false)->save($res);

                    } else if (1 < $day) {

                        $res_ret = [];

                        //计算日期
                        //
                        $regDate = date('Y-m-d', strtotime($startDate) - 3600 * 24 * ($day - 1));

                        if ($regDate >= $open_date) {

                            $calcDate        = $startDate;
                            $res_ret['date'] = $regDate;

                            //计算注册日期开始，第 $day 天的留存数

                            $res_ret['RET' . $day] = $this->llogin->getRET($regDate, $calcDate);
                            //dump($res_ret);

                            //更新注册日期开始，第 $day 天的留存数

                            $model->isUpdate(true)->save($res_ret, ['date' => $regDate]);
                        }
                    }
                }
            }
        }
    }
}
